package com.sjft.cloud.commons.security.rest;

import com.sjft.cloud.commons.core.constant.Constant;
import com.sjft.cloud.commons.core.func.Fn;
import com.sjft.cloud.commons.security.service.RedisClientDetailsService;
import com.sjft.cloud.commons.security.utils.ClientsUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;


/**
 * RestLoginSuccessHandler
 *
 * @author Jin
 */
@Slf4j
@AllArgsConstructor
public class RestOauth2LoginSuccessHandler implements AuthenticationSuccessHandler {
    private final ObjectMapper objectMapper;
    private final PasswordEncoder passwordEncoder;
    private final RedisClientDetailsService redisClientDetailsService;
    private final AuthorizationServerTokenServices authorizationServerTokenServices;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        try {
            ClientsUtils.ClientInfo client = ClientsUtils.buildClientInfo(request.getHeader(HttpHeaders.AUTHORIZATION));

            ClientDetails clientDetails = redisClientDetailsService.loadClientByClientId(client.getClientId());

            if (Fn.isNull(clientDetails)) {
                throw new UnapprovedClientAuthenticationException("请求头中未获取到 clientId ！");
            } else if (!passwordEncoder.matches(client.getClientSecret(), clientDetails.getClientSecret())) {
                throw new UnapprovedClientAuthenticationException("请求头 clientSecret 不正确！");
            }

            TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_SORTED_MAP, client.getClientId(), clientDetails.getScope(), "mobile");
            OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();
            oAuth2RequestValidator.validateScope(tokenRequest, clientDetails);
            OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
            OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
            OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
            oAuth2Authentication.setAuthenticated(true);
            response.setCharacterEncoding(Constant.UTF_8);
            response.setContentType(Constant.APPLICATION_JSON);
            PrintWriter printWriter = response.getWriter();
            printWriter.append(objectMapper.writeValueAsString(oAuth2AccessToken));

        } catch (Exception e) {
            throw new UnapprovedClientAuthenticationException(e.getMessage());
        }
    }
}
